function [G_final, S_final, F_final, nIter_final, objhistory_final] = DRCC(X, rowK, colK, rowW, colW, options, G, S, F)
% Dual Regularized Co-Clustering (DRCC)
%
% Input
%     X: (mFea x nSmp) data matrix 
%         mFea  ... number of words (vocabulary size)
%         nSmp  ... number of documents
%     rowK: number of row hidden factors
%     colK: number of column hidden factors
%     rowW: weight matrix of the affinity graph on features
%     colW: weight matrix of the affinity graph on samples
%     options: Structure holding all settings
%         options.rowLamda ... the regularization parameter. [default: 100]
%         options.colLamda ... the regularization parameter. [default: 100]
%
% You only need to provide the above four inputs.
%
% Optimization problem
%     min ||X - G S F'||^2 + rowLamda tr(G' Lg G)  + colLamda tr(F' Lf F)
%     s.t. G, S, F >=0.
% 
% References:
% [1] Quanquan Gu, Jie Zhou. "Co-Clustering on Manifolds", KDD, 2009.
%
%
%   Written by Liang Du (csliangdu AT gmail.com)
%

if min(min(X)) < 0
    error('Input should be nonnegative!');
end

if ~isfield(options,'error')
    options.error = 1e-5;
end
if ~isfield(options, 'maxIter')
    options.maxIter = [];
end

if ~isfield(options,'nRepeat')
    options.nRepeat = 10;
end

if ~isfield(options,'minIter')
    options.minIter = 30;
end

if ~isfield(options,'meanFitRatio')
    options.meanFitRatio = 0.1;
end

if ~isfield(options,'rowLamda')
    options.rowLamda = 100;
end

if ~isfield(options,'colLamda')
    options.colLamda = 100;
end

[nDim, nSmp] = size(X);

if isfield(options,'colLamda_nSmp') && options.colLamda_nSmp
    options.colLamda = options.colLamda * nSmp;    
end

if isfield(options,'rowLamda_nDim') && options.rowLamda_nDim
    options.rowLamda = options.rowLamda * nDim;    
end

if ~isfield(options,'Optimization')
    options.Optimization = 'Multiplicative';
end

if ~exist('G','var')
    G = [];
	S = [];
    F = [];
end

switch lower(options.Optimization)
    case {lower('Multiplicative')} 
        [G_final, S_final, F_final, nIter_final, objhistory_final] = DRCC_Multi(X, rowK, colK, rowW, colW, options, G, S, F);
    otherwise
        error('optimization method does not exist!');
end


    
        